import { Graph } from '@antv/x6'
import { Transform } from '@antv/x6-plugin-transform'
import { Selection } from '@antv/x6-plugin-selection'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { History } from '@antv/x6-plugin-history'

import { TreeNode, treeNodeList} from './nodes'
import { TreeEdge } from './edges'

export default function initGraph ({ container, nodeClick }) {
  console.log('asdfsd')
  // #region 初始化画布
  const graph = new Graph({
    container,
    grid: true,
    mousewheel: {
      enabled: true,
      zoomAtMousePosition: true,
      modifiers: 'ctrl',
      minScale: 0.5,
      maxScale: 3,
    },
    connecting: {
      allowLoop: false,
      router: 'manhattan',
      connector: {
        name: 'rounded',
        args: {
          radius: 8,
        },
      },
      anchor: 'center',
      connectionPoint: 'anchor',
      allowBlank: false,
      snap: {
        radius: 20,
      },
      createEdge () {
        // return new Shape.Edge({
        //   attrs: {
        //     line: {
        //       stroke: '#A2B1C3',
        //       strokeWidth: 2,
        //       targetMarker: {
        //         name: 'block',
        //         width: 12,
        //         height: 8,
        //       },
        //     },
        //   },
        //   zIndex: 0,
        // })

        return new TreeEdge()
      },
      validateConnection ({ targetMagnet }) {
        return !!targetMagnet
      },
    },
    highlighting: {
      magnetAdsorbed: {
        name: 'stroke',
        args: {
          attrs: {
            fill: '#5F95FF',
            stroke: '#5F95FF',
          },
        },
      },
    },
  })
  // #endregion

  // #region 使用插件
  graph
    .use(
      new Transform({
        resizing: true,
        rotating: true,
      }),
    )
    .use(
      new Selection({
        rubberband: true,
        showNodeSelectionBox: true,
      }),
    )
    .use(new Snapline())
    .use(new Keyboard())
    .use(new Clipboard())
    .use(new History())
  // #endregion

  

  // #region 快捷键与事件
  graph.bindKey(['meta+c', 'ctrl+c'], () => {
    const cells = graph.getSelectedCells()
    if (cells.length) {
      graph.copy(cells)
    }
    return false
  })
  graph.bindKey(['meta+x', 'ctrl+x'], () => {
    const cells = graph.getSelectedCells()
    if (cells.length) {
      graph.cut(cells)
    }
    return false
  })
  graph.bindKey(['meta+v', 'ctrl+v'], () => {
    if (!graph.isClipboardEmpty()) {
      const cells = graph.paste({ offset: 32 })
      graph.cleanSelection()
      graph.select(cells)
    }
    return false
  })

  // undo redo
  graph.bindKey(['meta+z', 'ctrl+z'], () => {
    if (graph.canUndo()) {
      graph.undo()
    }
    return false
  })
  graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
    if (graph.canRedo()) {
      graph.redo()
    }
    return false
  })

  // select all
  graph.bindKey(['meta+a', 'ctrl+a'], () => {
    const nodes = graph.getNodes()
    if (nodes) {
      graph.select(nodes)
    }
  })

  // delete
  graph.bindKey('backspace', () => {
    const cells = graph.getSelectedCells()
    if (cells.length) {
      graph.removeCells(cells)
    }
  })

  // zoom
  graph.bindKey(['ctrl+1', 'meta+1'], () => {
    const zoom = graph.zoom()
    if (zoom < 1.5) {
      graph.zoom(0.1)
    }
  })
  graph.bindKey(['ctrl+2', 'meta+2'], () => {
    const zoom = graph.zoom()
    if (zoom > 0.5) {
      graph.zoom(-0.1)
    }
  })

  // 控制连接桩显示/隐藏
  const showPorts = (ports, show) => {
    for (let i = 0, len = ports.length; i < len; i += 1) {
      ports[i].style.visibility = show ? 'visible' : 'hidden'
    }
  }
  graph.on('node:mouseenter', () => {
    const container = document.getElementById('graph-container')
    const ports = container.querySelectorAll(
      '.x6-port-body',
    )
    showPorts(ports, true)
  })
  graph.on('node:mouseleave', () => {
    const container = document.getElementById('graph-container')
    const ports = container.querySelectorAll(
      '.x6-port-body',
    )
    showPorts(ports, false)
  })
  // #endregion

  // 节点拖入后自动添加连线
  function autoAddEdge(cell, node) {
    let area = graph.getCellsBBox([cell])
    area = {x: area.x - 50, y: area.y - 100, width: area.width + 50, height: area.height + 100}
    let nodes = graph.getNodesInArea(area)
    nodes = nodes.filter(item => item.id!== node.id)

    if (nodes.length) {
      let parentNode = nodes[0]
      graph.addEdge(new TreeEdge(
        {
          source: {
            cell: parentNode.id,
            port: parentNode.ports.items.find(item => item.group == 'bottom').id
          },
          target: {
            cell: node.id,
            port: node.ports.items.find(item => item.group == 'top').id
          }
        }
      ))
    }
  }

  graph.on('node:added', ({cell, node}) => {
    // autoAddEdge(cell, node)
  })

  graph.on('node:removed', () => {
    nodeClick && nodeClick(null)
  })

  graph.on('node:click', ({node}) => {
    nodeClick && nodeClick(node)
  })

  function setCollapsedButton(node) {
    try {
      let outNodes = graph.getNeighbors(node, { incoming: false, outgoing: true })
      if (treeNodeList.includes(node.shape)) {
        node.toggleButtonVisibility(outNodes.length > 0)
      }
    } catch (err) {
      console.log(err)
    }
  }

  graph.on('edge:added', (event) => {
    if (!event.edge.target.cell) {
      return
    }
    const { edge } = event
    const sourceCell = graph.getCellById(edge.source.cell)
    const targetCell = graph.getCellById(edge.target.cell)
    setCollapsedButton(sourceCell)
    setCollapsedButton(targetCell)
  })

  graph.on('edge:connected', (event) => {
    if (!event.edge.target.cell) {
      return
    }
    const { edge } = event
    const sourceCell = graph.getCellById(edge.source.cell)
    const targetCell = graph.getCellById(edge.target.cell)
    setCollapsedButton(sourceCell)
    setCollapsedButton(targetCell)
  })

  graph.on('edge:removed', (event) => {
    const { edge } = event
    const sourceCell = graph.getCellById(edge.source.cell)
    setCollapsedButton(sourceCell)
  })

  graph.on('node:collapse', ({ node }) => {
    node.toggleCollapse()
    const collapsed = node.isCollapsed()
    const run = (pre) => {
      const succ = graph.getSuccessors(pre, { distance: 1 })
      if (succ) {
        succ.forEach((node) => {
          node.toggleVisible(!collapsed)
          if (!node.isCollapsed()) {
            run(node)
          }
        })
      }
    }
    run(node)
  })

  // #region 初始化图形
  const ports = {
    groups: {
      top: {
        position: 'top',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: {
              visibility: 'hidden',
            },
          },
        },
      },
      right: {
        position: 'right',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: {
              visibility: 'hidden',
            },
          },
        },
      },
      bottom: {
        position: 'bottom',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: {
              visibility: 'hidden',
            },
          },
        },
      },
      left: {
        position: 'left',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: {
              visibility: 'hidden',
            },
          },
        },
      },
    },
    items: [
      {
        group: 'top',
      },
      // {
      //   group: 'right',
      // },
      {
        group: 'bottom',
      },
      // {
      //   group: 'left',
      // },
    ],
  }

  Graph.registerNode(
    'custom-rect',
    {
      inherit: 'rect',
      width: 66,
      height: 36,
      attrs: {
        body: {
          strokeWidth: 1,
          stroke: '#5F95FF',
          fill: '#EFF4FF',
        },
        text: {
          fontSize: 12,
          fill: '#262626',
        },
      },
      ports: { ...ports },
    },
    true,
  )

  Graph.registerNode(
    'custom-polygon',
    {
      inherit: 'polygon',
      width: 66,
      height: 36,
      attrs: {
        body: {
          strokeWidth: 1,
          stroke: '#5F95FF',
          fill: '#EFF4FF',
        },
        text: {
          fontSize: 12,
          fill: '#262626',
        },
      },
      ports: {
        ...ports,
        items: [
          {
            group: 'top',
          },
          {
            group: 'bottom',
          },
        ],
      },
    },
    true,
  )

  Graph.registerNode(
    'custom-circle',
    {
      inherit: 'circle',
      width: 45,
      height: 45,
      attrs: {
        body: {
          strokeWidth: 1,
          stroke: '#5F95FF',
          fill: '#EFF4FF',
        },
        text: {
          fontSize: 12,
          fill: '#262626',
        },
      },
      ports: { ...ports },
    },
    true,
  )

  Graph.registerNode(
    'custom-image',
    {
      inherit: 'rect',
      width: 40,
      height: 40,
      markup: [
        {
          tagName: 'rect',
          selector: 'body',
        },
        {
          tagName: 'image',
        },
        {
          tagName: 'text',
          selector: 'label',
        },
      ],
      attrs: {
        body: {
          stroke: '#5F95FF',
          fill: '#5F95FF',
        },
        image: {
          width: 20,
          height: 20,
          refX: 13,
          refY: 16,
        },
        label: {
          refX: 3,
          refY: 2,
          textAnchor: 'left',
          textVerticalAnchor: 'top',
          fontSize: 10,
          fill: '#fff',
        },
      },
      ports: { ...ports },
    },
    true,
  )

  return graph
}

export function createImageNodes(graph, imageList) {
  return imageList.map((item) =>
    graph.createNode({
      shape: 'custom-image',
      label: item.label,
      attrs: {
        image: {
          'xlink:href': item.image,
        },
      },
    }),
  )
}